/*
 * author : Dinh Ngoc Tuan Vu (A0092633)
 */
package sg.edu.nus.iss.team4ft.ui;

import java.awt.BorderLayout;
import java.awt.Checkbox;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ItemEvent;
import java.util.ArrayList;
import java.util.Date;

import sg.edu.nus.iss.team4ft.exception.InvalidOperationException;
import sg.edu.nus.iss.team4ft.service.*;
import sg.edu.nus.iss.team4ft.util.AppConstant;
import sg.edu.nus.iss.team4ft.util.DateUtil;

public class PlanControl extends Panel {

	private static final long serialVersionUID = 1L;
	
	private DateControl dateControl;private Checkbox cbPlan = new Checkbox();
	private Label dateText = new Label();
	private Label phoneNumber = new Label();

	ArrayList<FeatureControl> featureControls = new ArrayList<FeatureControl>();
	Panel panelFeatures = new Panel(new GridLayout(0,1));
	
	private Plan actualPlan;
	private Plan plan;
	private PlanCode planCode;
	private Mode mode;

	private boolean isPlanSelected = false;	
	
	private CheckboxTestListener cbPlanListener = new CheckboxTestListener(){
		public void itemStateChanged(ItemEvent arg0){
			toggleVisibility();
		}
	};
	
	public PlanControl(PlanCode planCode, Mode mode) throws Exception{
		this.setPlanCode(planCode);
		loadControlValues(mode);
		this.setMode(mode);
	}
	
	public PlanControl(Plan plan, Mode mode) throws Exception{
		isPlanSelected = true;
		this.mode = mode;
		this.setPlanCode(plan.getPlanCode());
		
		//If the plan was deactivated, do not show it in the edit mode. 
		//Because, the plan is maintained only for history.		
		//So the user can activate it as a new plan.
		if(plan != null && plan.getEndDate() == null)
			setPlan(plan);
		
		loadControlValues(mode);
		this.setMode(mode);		
	}
	
	private void loadControlValues(Mode mode) throws Exception {
			try{
				this.cbPlan.setPreferredSize(new java.awt.Dimension(120, 25));
				this.cbPlan.setLabel(getPlanName());
				this.cbPlan.addItemListener(cbPlanListener);
				dateControl = new DateControl(AppConstant.ACTIVATE, mode);
				dateText.setFont(new java.awt.Font("Arial",2,10));
				
				if(this.plan != null)
					this.dateText.setText("[" + AppConstant.ACTIVATE + DateUtil.defaultFormat(plan.getStartDate()) + "]");
		

				//dateText.setText(AppConstant.ACTIVATE + DateUtil.defaultFormat(DateUtil.getDate()));
				Panel p = new Panel(new BorderLayout(0,1));
				p.add("West", this.cbPlan);
				p.add("Center", this.dateControl);
				p.add("East", this.dateText);
				
				if(this.plan != null){
					if(this.plan instanceof VoicePlan){
						String text = "Mobile Number: ";
						
					if(this.plan instanceof DigitalVoice)
						text = "Line Number: ";
		
					phoneNumber.setText(text + ((VoicePlan)this.plan).getTelephoneNumberInString());						
					phoneNumber.setForeground(Color.BLUE);
					phoneNumber.setFont(new java.awt.Font("Arial",2,10));
					}
				}
				
				if(planCode != PlanCode.CableTV)
					p.add("South", this.phoneNumber);
				
				this.setLayout(new BorderLayout(0,1));
				this.add("North",p);
				
				if(this.actualPlan == null)
						this.actualPlan = initPlan();
				
				loadPlanFeature(mode);
				this.panelFeatures.setVisible(true);
				this.add("West",new Panel());
				this.add("Center",this.panelFeatures);
			}
			catch (Exception e) {
				throw e;
			}
	}

	private void loadPlanFeature(Mode mode) throws CloneNotSupportedException {
		FeatureControl locaCall;
		FeatureControl internationalCall;
		FeatureControl roamingCall;
		FeatureControl dataService;
		FeatureControl callTransfer;
		
		Feature lc = null, ic = null, rc = null, ds = null, ct = null;
		
		if(plan != null){
			lc = plan.getFeature(FeatureCode.LocalCall);
			ic = plan.getFeature(FeatureCode.InternationalCall);
			rc = plan.getFeature(FeatureCode.RoamingCall);
			ds = plan.getFeature(FeatureCode.DataService);
			ct = plan.getFeature(FeatureCode.CallTransfer);
		}
		
		if(lc != null  && lc.getEndDate() == null)
			locaCall = new FeatureControl(lc, mode, this);
		else
			locaCall = new FeatureControl(FeatureCode.LocalCall,mode, this);
			
		if(ic != null  && ic.getEndDate() == null)
			internationalCall = new FeatureControl(ic , mode, this);
		else
			internationalCall = new FeatureControl(FeatureCode.InternationalCall, mode, this);
		
		if(rc != null && rc.getEndDate() == null)
			roamingCall = new FeatureControl(rc, mode, this);
		else
			roamingCall = new FeatureControl(FeatureCode.RoamingCall, mode, this);

		if(ds != null && ds.getEndDate() == null)
			dataService = new FeatureControl(ds, mode, this);
		else
			dataService = new FeatureControl(FeatureCode.DataService, mode, this);
		
		if(ct != null && ct.getEndDate() == null)
			callTransfer = new FeatureControl(ct, mode, this);
		else
			callTransfer = new FeatureControl(FeatureCode.CallTransfer, mode, this);
		

		locaCall.setVisible(true);
		internationalCall.setVisible(true);
		roamingCall.setVisible(true);
		dataService.setVisible(true);
		callTransfer.setVisible(true);
		
		switch(planCode){
			case DigitalVoice:
				featureControls.add(locaCall);
				featureControls.add(internationalCall);
				featureControls.add(callTransfer);
				this.panelFeatures.setLayout(new GridLayout(3,1));
				this.panelFeatures.add(locaCall);
				this.panelFeatures.add(internationalCall);
				this.panelFeatures.add(callTransfer);
				break;
			case MobileVoice:
				featureControls.add(locaCall);
				featureControls.add(internationalCall);
				featureControls.add(dataService);
				featureControls.add(roamingCall);
				this.panelFeatures.setLayout(new GridLayout(4,1));
				this.panelFeatures.add(locaCall);
				this.panelFeatures.add(internationalCall);
				this.panelFeatures.add(dataService);
				this.panelFeatures.add(roamingCall);
				break;
			case CableTV:
				this.panelFeatures.setLayout(new GridLayout(5,1));
				for (String name : AppConstant.CHANNEL_NAMES) {
					Feature cs = null;
					FeatureControl channelService;
					if(plan != null)
						cs = plan.getFeature(name);
					
					if(cs != null)
						channelService = new FeatureControl(cs, mode, this);
					else
						channelService = new FeatureControl(FeatureCode.ChannelService, mode, name, this);
					featureControls.add(channelService);
					this.panelFeatures.add(channelService);
				}
				break;
		}			
	}
	
	public void toggleVisibility(){
		for (FeatureControl fc : featureControls) {
			fc.changeStateOnParentSelected(this.cbPlan.getState());
			fc.setEnabled(this.cbPlan.getState());
		}
		
		boolean isEnabled = this.cbPlan.getState();
		
		if(mode == Mode.Edit && isPlanSelected)
			isEnabled = !isEnabled;
		
		this.dateControl.setEnabled(isEnabled);	
	}

	private Plan initPlan() throws Exception {
		Plan plan = null;		
		try{
			Date d = null;
			try{
				d = this.dateControl.getDate();
			}catch (InvalidOperationException e) {
				//date is not valid. so continue
			}
			if(d == null)
				d = DateUtil.getDate();
			switch(planCode){
			case DigitalVoice:
				plan = new DigitalVoice(d);
				break;
			case MobileVoice:
				plan = new MobileVoice(d);
				break;
			case CableTV:
				plan = new CableTv(d);
				break;
			}
		}
		catch (Exception e) {
			throw e;
		}
		return plan;
	}
	
	private String getPlanName() {
		switch(planCode){
		case DigitalVoice:
			return AppConstant.DIGITAL_VOICE_PLAN;
		case MobileVoice:
			return AppConstant.MOBILE_VOICE_PLAN;
		case CableTV:
			return AppConstant.CABLE_TV_FEATURE;
		default:
				return "";
		}
	}
	
	public boolean isValidToSave(){
		return true;
	}

	public Plan getPlan() throws Exception {
		try{
			Date date = this.dateControl.getDate();
			if(this.plan == null){
				if(this.cbPlan.getState())
					this.plan = initPlan();
			}
			else{
				if(date!= null){
					if(this.cbPlan.getState())
						this.plan.setStartDate(this.dateControl.getDate());
					if(!this.cbPlan.getState())
						this.plan.setEndDate(this.dateControl.getDate());
				}
			}
			
			for (FeatureControl fc : featureControls) {
				Feature f = null;
				if(this.plan != null && !this.cbPlan.getState())
					f = fc.getFeature(date);
				else
					f = fc.getFeature(null);
				if(f!= null){
					f.setPlan(this.plan);
					this.plan.subscripeNewFeature(f);
				}
			}
			return plan;
		}catch (Exception e) {
			errorNotification();
			throw e;
		}
	}

	private void errorNotification() {
		this.setBackground(Color.RED);
		this.repaint();
	}
	public void setPlan(Plan plan) {
		this.setActualPlan(plan);
		this.plan = plan;
	}

	public Mode getMode() {
		return mode;
	}

	public void setMode(Mode mode) {
		this.mode = mode;
		this.dateControl.setMode(mode);
		for (FeatureControl fc : this.featureControls) {
			fc.setMode(mode);
		}
		
		if(this.mode == Mode.New)
			 modeNew();
		else if(this.mode == Mode.Edit)
			 modeEdit();
		else if(this.mode == Mode.View)
			 modeView();
	}
	
	private void modeNew(){
		this.dateControl.setEnabled(false);
		for (FeatureControl fc : featureControls) {
			fc.setEnabled(false);
		}
	}
	
	private void modeEdit(){
		
		if(isPlanSelected && plan != null){
			this.cbPlan.setState(true);
			this.dateControl.setEnabled(false);
			this.dateControl.setText(AppConstant.DEACTIVATE);
			for (FeatureControl fc : featureControls) {
				fc.setEnabled(true);
			}
		}
		else{
			this.dateControl.setEnabled(false);
			for (FeatureControl fc : featureControls) {
				fc.setEnabled(false);
			}
		}
	}
	
	private void modeView(){	
		//Not required. UI changed
	}

	public PlanCode getPlanCode() {
		return planCode;
	}

	public void setPlanCode(PlanCode planCode) {
		this.planCode = planCode;
	}

	public Plan getActualPlan() {
		return actualPlan;
	}

	public void setActualPlan(Plan actualPlan) {
		this.actualPlan = actualPlan;
	}

}
